iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 15
0
Data Technology

30天python雜談系列 第 15

版本差異雜談之五———懶得談open了&加個range充字數

  • 分享至 

  • xImage
  •  

python 版本差異雜談之五

昨天說到了open函數的newline參數在read模式下的行為,write模式就比較簡單了,若是預設的模式"universal newline",會把寫入的'\n'轉譯成作業系統預設的換行字符,若想知道當前作業系統預設的換行字符,可以用print(repr(os.linesep))來查看,newline=''不會做任何轉譯,其餘的模式就是把寫入的'\n'轉譯成自己想要的型式,這就讓大家自己去測試吧。

阿阿,我們一直都在講python3的檔案換行處理,接下來來看看python2是怎麼做的,因為版本差異雜談第3篇有提到python2字串的輸出行為,要同時輸出example_file裏面的中文以及換行符號是不容易的,這樣導致我們很難在example_file.read()中觀察到轉譯行為,所以容我稍微修改一下example_file的內容:

In python2 shell:
>>> example_file=open('example_newline','wt')
>>> example_file.write('the 1st line\nthe 2nd line\rthe 3rd line\r\nthe 4th line') # 讓他變成英文的

開始測試:

In python2 shell:
>>> example_file=open('example_newline','rt')
>>> for line in example_file: # 只辨認'\n',而且不會轉譯字符
...     print(repr(line))
... 
'the 1st line\n'
'the 2nd line\rthe 3rd line\r\n'
'the 4th line'
>>> example_file=open('example_newline','rU')
>>> for line in example_file: # 相當於"universal newline"
...     print(repr(line))
... 
'the 1st line\n'
'the 2nd line\n'
'the 3rd line\n'
'the 4th line'
>>> example_file=open('example_newline','rb')
>>> for line in example_file: # 感覺rt和rb的讀取行為是一致的
...     print(repr(line))
... 
'the 1st line\n'
'the 2nd line\rthe 3rd line\r\n'
'the 4th line'
>>> 

恩....我發現似乎用了repr的輸出方法就省去了很多麻煩,很輕鬆就能辨認換行符號以及轉譯行為,這樣我們昨天也不需要為了探討'\r'造成的輸出影響做如此多的探討,在這裡先跟大家說聲抱歉XD,在這裡python2的open函數預設是只會辨認'\n'為換行(我不知道在其他作業系統會換成辨認其他換行符號,這就請和linux系統不一樣的人試試看了),且不會轉譯,而若在mode參數裡添加U,就代表"universal newline",大概是這樣,我好像查不到更多資料了,我盡力了,然後寫入模式大家就自己試試看拉哈哈!newline的問題讓我這兩天好煩燥阿!感覺很煩瑣,如果還在用python2的人,又遇到關於換行符號的問題,就請你們用一下io.open囉,那裡面的newline參數跟python3是一樣的,不要硬糾結在python2的open裡。

來講講open函數其他不同之處,在python3的mode參數中還多新增了一個選項,也就是'x',相信大家常有一個經驗,在python用w mode寫入一些檔案時不小心覆寫了一個已存在的檔案,雖然可以在寫入前事先檢查檔案是否存在,比如說用os.path.exists,但那明顯複雜多了,現在python3提供了一個很簡便的方法,就是x mode,和w mode行為相同,但會再寫入之前先檢查是否有檔案存在,如果檔案存在就會跳出FileExistsError的例外。

好,open函數就此打住,懶的再去鑽研裏面的細碎功能了(逃)。

差異五:range()與xrange()

range()對眾多python愛好者肯定是非常熟悉了,其可以產生一個連續的等差數列,若在某些需要計數的for迴圈用上range()是很方便的,而在python2中還有一個xrange()就需要說一下了,雖然其在for迴圈裡的行為和range()無異,但在本值上卻有不同,range是直接產生並回傳一個list,所以for i in range(5)和for i in [0,1,2,3,4]是一樣的。

但xrange回傳的卻是一個xrange物件,他產生值的方式被稱做是"lazy evaluation",當你真的要跟他取值的時候,他才會去計算並把值return回來給你,而不像range()一樣很勤勞的把所有東西生出來(也就是生出一個list存在記憶體裡)等著你去取用,所以xrange在for迴圈中的記憶體用量比起range是少很多的,我們來比較一下其效能如何:

# 先寫一個測試檔python
import time

ts = time.time()

for i in range(10000000):
    a = i

te = time.time()
print ("range's time consume: %f" % (te-ts))

ts = time.time()

for i in xrange(10000000):
    a = i

te = time.time()
print ("xrange's time consume: %f" % (te-ts))

In bash:
$ python test.py
range's time consume: 2.116970
xrange's time consume: 1.510061

明顯效能上是xrange也是優於range的,主要原因是xrange少了記憶體的allocate還有list初期的initinalize....好吧不要太離題XD,總之其中還有非常多的細節可以探討,我也不盡然都講的很精確,但大概就是這樣,再回來講python2和python3的差別再哪吧!

在python3中range()已經做成了類似xrange(),所以在python3中已經沒有xrange()函數了,結束。(其實剛剛對xrange的說明主要是來充字數的)

阿阿其實這個xrange的行為就跟generator很相似,至於generator過幾天應該就會講了,在這裡先預告一下。


上一篇
版本差異雜談之四———open之亂談無極限
下一篇
版本差異雜談之六———pos_args與kw_args之亂
系列文
30天python雜談30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言